export class Camera {
	constructor(viewer) {
		this.viewer = viewer;
		this.cameraStatusList = [];
		this.HEAD = '';
		this.isMove = false;
	}

	async getCameraParams(original) {
		const cameraStatus = this.viewer.getCameraStatus();
		if (original) {
			return cameraStatus;
		}
		if (this.viewer._withoutLatLon) return null;
		const target = new THREE.Vector3(
			cameraStatus.target.x,
			cameraStatus.target.y,
			cameraStatus.target.z
		);
		const position = new THREE.Vector3(
			cameraStatus.position.x,
			cameraStatus.position.y,
			cameraStatus.position.z
		);
		const direction = target.clone().sub(position);
		const cameraUp = this.viewer.getViewer().camera.realUp.y > 0 ? 1 : -1;
		const yawDir = new THREE.Vector2(direction.x * cameraUp, direction.y * cameraUp);
		const yawAxis = new THREE.Vector2(0, 1);
		let yaw = yawDir.angle() - yawAxis.angle();
		yaw < 0 && (yaw += Math.PI * 2);
		const pitchDir = new THREE.Vector2(
			Math.sqrt(direction.x * direction.x + direction.y * direction.y) * cameraUp,
			direction.z
		);
		let pitch = pitchDir.angle();
		pitch > Math.PI && (pitch -= Math.PI * 2);

		const latLon = this.viewer._getLatLonByPosition(position);
		return {
			lat: latLon.lat,
			lon: latLon.lon,
			height: position.z,
			heading: yaw,
			pitch,
			roll: 0
		};
	}

	async flyTo(options) {
		if (this.viewer._withoutLatLon) return null;
		const status = this.getCameraStatusFromParams(options);
		this.viewer.setCameraStatus(status);
	}

	async homeView() {
		this.viewer.setCameraStatus(
			this.viewer.getCustomHomeview() || this.viewer.getDefaultHomeview()
		);
	}

	async topView() {
		this.viewer.setView('Top');
	}

	async zoomIn() {
		this.viewer.zoomIn();
	}

	async zoomOut() {
		this.viewer.zoomOut();
	}

	async maxZoomDistance(distance) {
		const bbox = this.viewer.getViewer().getScene().getBoundingBox();
		const vect = new THREE.Vector3();
		bbox.getSize(vect);
		const length = vect.length() * 1.2;
		const factor = distance / length;
		this.viewer.setMaximalRangeofCamera(factor);
		return factor;
	}

	async minZoomDistance(distance) {
		this.viewer.setMaximalRangeofCamera(18, 30);
	}

	getCameraStatusFromParams(config) {
		if (this.viewer._withoutLatLon) return null;
		const cameraStatus = this.viewer.getCameraStatus();
		console.log(cameraStatus, 'cameraStatus');
		let yaw = config.heading;
		yaw > Math.PI * 2 && (yaw -= Math.PI * 2);
		let pitch = config.pitch;
		pitch > Math.PI && (pitch -= Math.PI * 2);
		pitch < -Math.PI && (pitch += Math.PI * 2);
		let position = this.viewer._getPositionByLatLon({
			lat: config.lat,
			lon: config.lon,
			height: config.height
		});
		position = new THREE.Vector3(position.x, position.y, position.z);
		const yawDir = new THREE.Vector2(0, 1).rotateAround(new THREE.Vector2(0, 0), yaw);
		const dirZ = Math.tan(pitch);
		const direction = new THREE.Vector3(yawDir.x, yawDir.y, dirZ);
		direction.normalize();
		const cameraDistance = position.clone().length();
		const cameraOffset = direction.multiplyScalar(cameraDistance);
		cameraStatus.position = position;
		cameraStatus.target = position.clone().add(cameraOffset);
		cameraStatus.up = { x: 0, y: 0, z: 1 };
		return cameraStatus;
	}

	addEventListener() {
		let timeout = null;
		let flag = true;
		this.camera = new Camera(viewer);
		this.viewer.addEventListener(
			Glodon.Bimface.Viewer.Viewer3DEvent.CameraPositionChanged,
			(status) => {
				if (flag) {
					flag = false;
					let isMove = this.isMove;
					if (isMove == false) {
						this.cameraStatusList.push(status);
						this.HEAD = this.cameraStatusList.length - 1;
					}
					timeout = setTimeout(() => {
						flag = true;
						clearTimeout(timeout);
					}, 1000);
				}
			}
		);
	}

	async undo() {
		this.isMove = true;
		const cameraStatusList = this.cameraStatusList;
		const cameraStatusLen = cameraStatusList.length;
		if (cameraStatusLen > 1) {
			let HEAD = this.HEAD + 1;
			this.viewer.setCameraStatus(cameraStatusList[HEAD]);
			if (this.HEAD >= cameraStatusLen - 1) {
				this.HEAD = cameraStatusList.length - 2;
			} else {
				this.HEAD = HEAD;
			}
		}
	}

	async redo() {
		console.log(this.HEAD, 'redo.HEAD');
		this.isMove = true;
		const cameraStatusList = this.cameraStatusList;
		const cameraStatusLen = cameraStatusList.length;
		if (cameraStatusLen > 1) {
			let HEAD = this.HEAD - 1;
			this.viewer.setCameraStatus(cameraStatusList[HEAD]);
			if (this.HEAD <= 0) {
				this.HEAD = 1;
			} else {
				this.HEAD = HEAD;
			}
		}
	}
}
